Skip to content

Conversation

@clairekinde11
Copy link
Contributor

@clairekinde11 clairekinde11 commented Sep 29, 2025

New topic about JWT decoding, referencing the Kinde utils we have to do this.
Needs review by @DanielRivers at minimum.

Summary by CodeRabbit

  • Documentation
    • New public guide on decoding and validating JSON Web Tokens (JWTs) with Kinde libraries.
    • Includes installation steps, basic and type-safe JavaScript/TypeScript examples, and manual decoding approaches for browser, Node, and universal environments.
    • Details validation workflows, a security checklist, error-handling patterns, and practical use cases (displaying user info, feature flags, permissions).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 29, 2025

Walkthrough

Adds a new MDX documentation page at src/content/docs/build/tokens/decode-jwts.mdx that documents JWT structure, decoding vs. validation, Kinde decoder/validator usage, manual decoding patterns (Browser/Node/universal/TypeScript), validation checklist, error handling, use cases, and security best practices.

Changes

Cohort / File(s) Summary
Docs — JWT decoding/validation guide
src/content/docs/build/tokens/decode-jwts.mdx
New MDX page with front-matter metadata and comprehensive content covering JWT structure, decoding vs. validation, installation and usage of Kinde libraries (@kinde/jwt-decoder, @kinde/jwt-validator), basic and type-safe examples, manual decoding patterns for Browser/Node/universal, TypeScript interfaces, validation checklist, error handling patterns, practical use cases, and security considerations.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

  • Verify front-matter metadata (title, page_id, topics, languages, updated date).
  • Quick pass for technical accuracy and clarity of code samples and security recommendations.

Poem

I nibble claims beneath the moon,
I parse the header, hum a tune.
With whiskered logic, tokens freed,
I hop through checks and plant a seed.
A rabbit’s guide — decode with speed. 🥕✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a new documentation guide about decoding JSON Web Tokens, which aligns with the PR's primary objective of introducing JWT decoding guidance.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Feat/DecodeJWTs

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (8)
src/content/docs/build/tokens/decode-jwts.mdx (8)

30-30: Update the “updated” date to this PR’s timeline.

Current: 2024-01-15. Suggest 2025-09-29 for accuracy.

-updated: 2024-01-15
+updated: 2025-09-29

Please confirm the doc site’s date policy (authored vs updated).


114-125: Show explicit expected algorithms and domain/issuer guidance.

Add recommended options and a note to pin expected algs (e.g., RS256) and issuer.

-const validationResult = await validateToken({
-  token: "eyJhbGc...",
-  domain: "https://your-subdomain.kinde.com"
-});
+const validationResult = await validateToken({
+  token: "eyJhbGc...",
+  domain: "https://your-subdomain.kinde.com",
+  // Optional but recommended hardening:
+  expectedAlgs: ["RS256"],
+  expectedIssuer: "https://your-subdomain.kinde.com",
+});

I can add a short “why pin algorithms” callout if helpful.


166-191: Provide a complete TS implementation rather than a placeholder.

Avoid “Implementation same as above”; include the base64url helper and typed return.

-interface DecodedJWT {
+interface DecodedJWT {
   header: JWTHeader;
   payload: JWTPayload;
   signature: string;
 }
 
-function decodeJWT(token: string): DecodedJWT {
-  // Implementation same as above
-}
+const b64urlToString = (b64url: string): string => {
+  const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');
+  const padded = b64 + '==='.slice((b64.length + 3) % 4);
+  // Browser vs Node
+  return typeof atob === 'function'
+    ? decodeURIComponent(escape(atob(padded)))
+    : Buffer.from(padded, 'base64').toString('utf8');
+};
+
+export function decodeJWT(token: string): DecodedJWT {
+  const parts = token.split('.');
+  if (parts.length !== 3) throw new Error('Invalid JWT format');
+  const header = JSON.parse(b64urlToString(parts[0])) as JWTHeader;
+  const payload = JSON.parse(b64urlToString(parts[1])) as JWTPayload;
+  return { header, payload, signature: parts[2] };
+}

197-201: Tighten the security bullets with explicit “don’t trust until validated.”

Clarify sequencing to prevent misinterpretation.

-**Decoding vs. Validation**: Decoding a JWT only extracts the payload - it doesn't verify the token's authenticity or integrity.
-**Always Validate**: After decoding, always validate the token using proper cryptographic verification.
+**Decoding vs. Validation**: Decoding only parses claims; it does not prove authenticity/integrity.
+**Always Validate**: Perform cryptographic validation (signature + claims) and only then trust any decoded data.

204-212: Expand the validation checklist (alg, kid/JWKS, nbf/leeway, issuer, audience).

Add commonly missed checks and adjust terminology.

-When validating JWTs, ensure you:
+When validating JWTs, ensure you:
 - Verify the token signature using the public key
 - Check the `iss` (issuer) claim matches your Kinde domain
 - Validate the `aud` (audience) claim
 - Verify the `exp` (expiration) claim
 - Check the `iat` (issued at) claim is reasonable
 - Validate any custom claims specific to your application
+- Enforce expected `alg` (e.g., RS256) and reject `none` or unexpected algorithms
+- Use `kid` to select the correct key from JWKS and cache JWKS with rotation in mind
+- Check `nbf` (not before) and allow small clock skew (e.g., ±60s leeway)
+- For OIDC ID tokens, also verify `nonce` when applicable

I can add a short JWKS caching callout if you want.


245-260: Harden feature‑flag access with nullish chaining and typing.

Avoid runtime errors when claims are absent.

-function checkFeatureFlag(token, flagName) {
+function checkFeatureFlag(token, flagName) {
   try {
     const decoded = jwtDecoder(token);
-    const featureFlags = decoded.payload.feature_flags;
-    
-    if (featureFlags && featureFlags[flagName]) {
-      return featureFlags[flagName].v; // 'v' is the value
-    }
-    
-    return false;
+    const v = decoded?.payload?.feature_flags?.[flagName]?.v;
+    return v ?? false;
   } catch (error) {
     console.error('Failed to check feature flag:', error);
     return false;
   }
 }

306-308: Rephrase “Validate Before Decoding.”

You must parse to validate; intent is “don’t trust decoded contents until validated.”

-**Validate Before Decoding**: Always validate the token's signature and claims before trusting the decoded payload.
+**Validate before trusting**: Parse, validate signature and claims, then trust the decoded payload.

68-75: Add explicit JWTDecoded import and tighten the decoded payload example

Import the exported JWTDecoded type and pass a concrete payload shape to jwtDecoder:

-import { jwtDecoder } from "@kinde/jwt-decoder";
+import { jwtDecoder, type JWTDecoded } from "@kinde/jwt-decoder";

Define a custom payload type and apply it:

-const decodedToken = jwtDecoder("eyJhbGc...");
+type MyClaims = JWTDecoded["payload"] & {
+  custom_claim?: string;
+  feature_flags?: Record<string, { v: unknown }>;
+};
+
+const decodedToken = jwtDecoder<MyClaims>("eyJhbGc...");

Apply the same pattern in the example at lines 79–90.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d88d65d and 94210b3.

📒 Files selected for processing (1)
  • src/content/docs/build/tokens/decode-jwts.mdx (1 hunks)
🔇 Additional comments (2)
src/content/docs/build/tokens/decode-jwts.mdx (2)

5-11: Inspect front-matter in decode-jwts.mdx
Please confirm presence and naming of sdk or sdks key in the front-matter once we have the file’s first lines.


112-112: Remove unused type import
jwtValidationResponse isn’t referenced in this file; drop it to avoid confusion.

-import { validateToken, type jwtValidationResponse } from "@kinde/jwt-validator";
+import { validateToken } from "@kinde/jwt-validator";

@tamalchowdhury tamalchowdhury changed the title New topic - Decode JWTs feat: Guide - Decoding JSON Web Tokens Nov 27, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/content/docs/build/tokens/decode-jwts.mdx (1)

304-304: Minor style: Replace "only" with more varied language.

To improve readability and flow, consider rephrasing "should only be used for display purposes" with an alternative structure.

Apply this diff for improved style:

-- **Never Trust Client-Side Decoding**: Client-side decoding should only be used for display purposes, not for security decisions.
+- **Never Trust Client-Side Decoding**: Client-side decoding is intended for display purposes only and must not be used for security decisions.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 94210b3 and 9ff2fe2.

📒 Files selected for processing (1)
  • src/content/docs/build/tokens/decode-jwts.mdx (1 hunks)
🧰 Additional context used
🪛 LanguageTool
src/content/docs/build/tokens/decode-jwts.mdx

[style] ~304-~304: Consider replacing ‘only’ with a different word to let your writing stand out.
Context: ...Decoding**: Client-side decoding should only be used for display purposes, not for s...

(ONLY_EXCLUSIVELY_STYLE)

🔇 Additional comments (2)
src/content/docs/build/tokens/decode-jwts.mdx (2)

3-4: ✓ Terminology corrected from previous review feedback.

Title and keywords now properly use "Decoding and validating" terminology instead of "Decrypting," avoiding confusion between JWS (signed) and JWE (encrypted) tokens. This aligns with the previous review guidance.

Also applies to: 16-16, 24-24, 33-33


1-415: Documentation comprehensively covers JWT decoding patterns with strong security guidance.

The document provides:

  • Clear introduction distinguishing decoding from validation
  • Two production-ready Kinde library options (Decoder & Validator) with installation and usage examples
  • Three manual decoding implementations (browser, Node.js, universal) with proper error handling
  • TypeScript types and interfaces for type-safe implementations
  • Practical use cases (user info, feature flags, permissions extraction)
  • Security considerations and validation checklist
  • Error handling patterns and best practices

This is a solid foundation for developers learning JWT handling. The previous review's terminology and base64 decoding concerns have been substantially addressed.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Nov 27, 2025

Deploying kinde-docs-preview with  Cloudflare Pages  Cloudflare Pages

Latest commit: a976789
Status: ✅  Deploy successful!
Preview URL: https://5ae2cef2.kinde-docs-preview.pages.dev
Branch Preview URL: https://feat-decodejwts.kinde-docs-preview.pages.dev

View logs

@tamalchowdhury tamalchowdhury self-assigned this Nov 27, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/content/docs/build/tokens/decode-jwts.mdx (1)

311-311: Minor: Consider rewording to strengthen impact.

The phrase "should only be used for display purposes" is clear, but you can strengthen it by restructuring to emphasize the security principle: "Client-side decoding is suitable only for display; do not make security decisions based on client-side decoded payloads."

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ff2fe2 and c803483.

📒 Files selected for processing (1)
  • src/content/docs/build/tokens/decode-jwts.mdx (1 hunks)
🧰 Additional context used
🪛 LanguageTool
src/content/docs/build/tokens/decode-jwts.mdx

[style] ~311-~311: Consider replacing ‘only’ with a different word to let your writing stand out.
Context: ...Decoding**: Client-side decoding should only be used for display purposes, not for s...

(ONLY_EXCLUSIVELY_STYLE)

🔇 Additional comments (6)
src/content/docs/build/tokens/decode-jwts.mdx (6)

1-34: Front matter looks good.

Terminology has been correctly aligned to "decoding" and "validating" (not "decrypting"), and metadata is well-structured.


36-43: Clear introduction with appropriate emphasis on JWS.

The distinction between signed (JWS) and encrypted (JWE) tokens is clarified upfront, and the JWT structure explanation is well-presented.


44-121: Kinde libraries section is well-structured and practical.

Installation instructions and usage examples for both decoder and validator are clear and easy to follow.


262-279: Align TypeScript base64UrlDecode encoding to match cross-platform version.

The TypeScript implementation (line 273) uses .toString('binary') while the cross-platform version (line 230) uses .toString('utf-8'). For consistency and clarity, both should use 'utf-8', which is semantically correct since JWT payloads are UTF-8 encoded before base64url encoding.

Apply this diff to align with the cross-platform approach:

 function base64UrlDecode(str: string): string {
   // Replace Base64URL characters with Base64 characters
   let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
   
   // Add padding if needed (Base64 strings must be multiples of 4)
   while (base64.length % 4) {
     base64 += '=';
   }
   
   // Use Buffer in Node.js, atob in browser
   if (typeof globalThis.Buffer !== 'undefined') {
-    return globalThis.Buffer.from(base64, 'base64').toString('binary');
+    return globalThis.Buffer.from(base64, 'base64').toString('utf-8');
   } else if (typeof globalThis.atob !== 'undefined') {
     return globalThis.atob(base64);
   } else {
     throw new Error('Neither Buffer nor atob is available in this environment');
   }
 }

305-324: Security section is comprehensive and appropriate.

The validation checklist, security notes, and emphasis on validation before trusting the payload are well-articulated and important.


388-422: Error handling and best practices sections are solid.

The examples demonstrate defensive programming, and the best practices provide clear, actionable guidance for developers.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/content/docs/build/tokens/decode-jwts.mdx (1)

311-311: Minor style: Consider rewording to avoid "only."

Line 311 states "Client-side decoding should only be used for display purposes." Per style guidance, this could be rephrased as "Client-side decoding is suitable for display purposes" or "Client-side decoding should be limited to display purposes" for variety, but the current phrasing is clear and acceptable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c803483 and 7892c55.

📒 Files selected for processing (1)
  • src/content/docs/build/tokens/decode-jwts.mdx (1 hunks)
🧰 Additional context used
🪛 LanguageTool
src/content/docs/build/tokens/decode-jwts.mdx

[style] ~311-~311: Consider replacing ‘only’ with a different word to let your writing stand out.
Context: ...Decoding**: Client-side decoding should only be used for display purposes, not for s...

(ONLY_EXCLUSIVELY_STYLE)

🔇 Additional comments (6)
src/content/docs/build/tokens/decode-jwts.mdx (6)

1-34: Front matter and metadata look solid.

The documentation page is well-structured with comprehensive front matter, clear topic categorization, and appropriate audience/complexity settings. Content across the page correctly uses "decoding and validating" terminology and avoids earlier "decrypting" confusion.


44-121: Kinde library sections are clear and actionable.

Installation instructions, basic usage, and validation workflows are well-documented with type-safe examples. Examples correctly reference the Kinde packages (@kinde/jwt-decoder, @kinde/jwt-validator) and show both synchronous and async patterns.


132-235: Cross-platform manual decoding implementations are correct.

The browser (atob), Node.js (Buffer), and universal approaches all properly handle base64url padding and character replacement. The progression from environment-specific to universal is pedagogically sound for the audience.


262-279: TypeScript implementation properly handles cross-platform environments.

The function correctly checks for Buffer availability via globalThis and falls back to atob in browser contexts, with an error fallback for unexpected environments. Type annotations on interfaces and function parameters are accurate.


305-323: Security section appropriately emphasizes validation over decoding.

The distinction between "decoding vs. validation" is clearly stated, and the validation checklist covers signature, issuer, audience, expiration, and custom claims—all critical for production use.


325-414: Use cases and error handling patterns provide practical guidance.

Examples for displaying user info, feature flags, and permissions are realistic; error handling uses try-catch with graceful fallbacks. The safeDecodeJWT helper properly validates token structure before decoding.

@Arobce
Copy link
Contributor

Arobce commented Nov 27, 2025

@tamalchowdhury.

A few changes. I noticed the code is a bit outdated in some places.

image

Here, a normal JWT decoder would return.

// Output: { header: {...}, payload: {...}, signature: "..." }

But, Kinde's library just returns the payload. So, it would be best to get ride of that comment here.

image

For Validation and Decoding, the validation doesn't return a payload that can be used it just returns a { valid: true, message: 'Token is valid' }. So, the correct snipped would be:

import { validateToken } from "@kinde/jwt-validator";
import { jwtDecoder } from "@kinde/jwt-decoder";

const token = "ey..."; // your JWT here

const validateAndDecode = async () => {
  try {
    // Validate the token
    const result = await validateToken({
      token,
      domain: "https://your-subdomain.kinde.com",
    });

    if (result.valid) {
      console.log("Token is valid");

      // Decode after validation
      const decoded = jwtDecoder(token);
      console.log("Decoded payload:", decoded);
    } else {
      console.log("Token validation failed:", result.message);
    }

  } catch (error) {
    // The validator throws for JWKS or validation errors
    console.error("Token is invalid:", error);
  }
};

validateAndDecode();
  1. Under Common Usecases

The attributes shown their in the use cases aren't available by default. So, it would be better to make a note of that.

A message like "Just a heads-up: the example attributes aren’t part of the default setup. You will need to enable them from the Kinde dashboard." would be perfect.

i. Display user information

A separate payload object from jwtDecoder is not returned anymore. So, the correct implementation would be:

import { jwtDecoder } from "@kinde/jwt-decoder"

function displayUserInfo(token) {
  try {
    const payload = jwtDecoder(token);

    console.log(`User: ${payload.name || payload.email}`);
    console.log(`Organization: ${payload.org_code}`);
    console.log(`Permissions: ${payload.permissions?.join(', ')}`);

    return {
      name: payload.name,
      email: payload.email,
      organization: payload.org_code,
      permissions: payload.permissions || []
    }
  } catch (error) {
    console.error('Failed to decode token:', error);
    return null;
  }
}

ii. Checking Feature Flags

This is same as above.

import { jwtDecoder } from "@kinde/jwt-decoder"

function checkFeatureFlag(token, flagName) {
  try {
    const payload = jwtDecoder(token);

    const featureFlags = payload.feature_flags;

    if (featureFlags && featureFlags[flagName]) {
      return featureFlags[flagName].v;
    }

    return false;
  } catch (error) {
    console.error('Failed to check feature flag:', error);
    return false;
  }
}

iii. Extracting Permissions

Same as above.

import { jwtDecoder } from "@kinde/jwt-decoder"

export function getUserPermissions(token) {
  try {
    const payload = jwtDecoder(token)
    return payload.permissions || []
  } catch (error) {
    console.error('Failed to extract permissions:', error)
    return []
  }
}

Rest of it is perfect! Please, let me know if you need any help with this.

@tamalchowdhury
Copy link
Collaborator

Hi @Arobce thanks a lot for checking the code for accuracy. Would you be able to check the correctness of the 3 functions used for manual decoding?

@Arobce
Copy link
Contributor

Arobce commented Nov 27, 2025

@tamalchowdhury did that along with my other tests.

Its working perfectly.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/content/docs/build/tokens/decode-jwts.mdx (1)

402-420: Minor: Rephrase to avoid overuse of "only" (optional refactor).

Line 408 uses "only" in a way that can be strengthened for clarity. Consider:

-  - **Never Trust Client-Side Decoding**: Client-side decoding should only be used for display purposes, not for security decisions.
+  - **Never Trust Client-Side Decoding**: Use client-side decoding exclusively for display purposes; never rely on it for security decisions.

The security checklist and best practices sections are otherwise comprehensive and well-structured.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7892c55 and a976789.

📒 Files selected for processing (1)
  • src/content/docs/build/tokens/decode-jwts.mdx (1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.29.1)
src/content/docs/build/tokens/decode-jwts.mdx

[high] 69-69: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

🪛 LanguageTool
src/content/docs/build/tokens/decode-jwts.mdx

[style] ~408-~408: Consider replacing ‘only’ with a different word to let your writing stand out.
Context: ...Decoding**: Client-side decoding should only be used for display purposes, not for s...

(ONLY_EXCLUSIVELY_STYLE)

🔇 Additional comments (5)
src/content/docs/build/tokens/decode-jwts.mdx (5)

1-42: Terminology and structure are correct.

Front matter and introduction properly use "decoding/validation" terminology and accurately describe JWT structure. Prior terminology feedback has been appropriately addressed.


44-90: jwtDecoder behavior correctly documented.

The example output (line 75) correctly shows the payload only, not header and signature. This accurately reflects Kinde's jwtDecoder implementation per the PR feedback.


92-141: Validation and decoding flow is correct.

The example properly separates concerns: validateToken returns { valid, message } (not payload), flow checks result.valid before calling jwtDecoder, and error handling wraps with try/catch. This implements the recommended pattern from PR feedback.


143-323: Manual decoding implementations are cross-platform and correct.

Browser, Node.js, universal, and TypeScript implementations all properly handle environment detection and base64url decoding with padding. TypeScript version correctly uses globalThis.Buffer with browser fallback. Prior feedback on cross-platform support has been addressed.


69-69: Gitleaks flag is expected for documentation examples.

The example JWT on line 69 is a standard token used to demonstrate jwtDecoder output in documentation. This is not a real secret or credential and does not represent a security risk in this context. The alert is a false positive for documentation examples.

Comment on lines +327 to +361
### Displaying User Information

You can extract user information from decoded tokens, including email, organization code, feature flags, and permissions.

By default, the email claim is not included in the `access_token`. To enable it:

1. Go to **Application** > **View Details** > **Tokens** > **Access Token** and select **Customize**.
2. Enable the **Email (string)** claim.
3. Select **Save**.

If you need to access the user's full name and profile picture, use the `id_token` instead of the access token. The `id_token` includes these claims by default. You can decode the `id_token` using the same method as the access token. Learn more about [ID tokens](/build/tokens/about-id-tokens/).

```javascript
import { jwtDecoder } from "@kinde/jwt-decoder"

function displayUserInfo(token) {
try {
const payload = jwtDecoder(token)

// Note: Email must be enabled in token customization for access tokens
console.log(`User: ${payload.email}`)
console.log(`Organization code: ${payload.org_code}`)
console.log(`Permissions: ${payload.permissions?.join(", ")}`)

return {
email: payload?.email || "",
org_code: payload.org_code,
permissions: payload.permissions || [],
}
} catch (error) {
console.error("Failed to decode token:", error)
return null
}
}
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add disclaimers for org_code and permissions attributes.

The "Displaying User Information" section documents that email requires dashboard enablement (lines 331–335), but similar disclaimers are missing for org_code and permissions attributes accessed on lines 348–349. Per PR feedback, attributes not available by default should be documented as requiring Kinde dashboard enablement.

Add a note clarifying which attributes are optional or require configuration:

 If you need to access the user's full name and profile picture, use the `id_token` instead of the access token. The `id_token` includes these claims by default. You can decode the `id_token` using the same method as the access token. Learn more about [ID tokens](/build/tokens/about-id-tokens/).
 
+**Note:** Additional attributes like `org_code` and `permissions` may require configuration in your Kinde application. Check [token customization documentation](#) to enable these claims.
+
 ```javascript
🤖 Prompt for AI Agents
In src/content/docs/build/tokens/decode-jwts.mdx around lines 327 to 361, add
brief disclaimers stating that org_code and permissions are not included by
default and must be enabled/configured in the Kinde dashboard (similar to the
email note): update the explanatory text above the code block and adjust the
comments inside the example to mention that org_code and permissions require
dashboard customization and may be undefined, and change the returned object/log
lines to defensively handle missing org_code and permissions (e.g., default to
empty string/array).

Comment on lines +363 to +384
### Checking Feature Flags

```javascript
import { jwtDecoder } from "@kinde/jwt-decoder"

function checkFeatureFlag(token, flagName) {
try {
const payload = jwtDecoder(token);

const featureFlags = payload.feature_flags;

if (featureFlags && featureFlags[flagName]) {
return featureFlags[flagName].v;
}

return false;
} catch (error) {
console.error('Failed to check feature flag:', error);
return false;
}
}
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add disclaimer for feature_flags attribute.

The "Checking Feature Flags" example accesses payload.feature_flags without documenting that this attribute requires enablement in the Kinde dashboard. Per PR feedback, optional attributes should be documented as needing configuration.

Add a note before or within the code example:

 ### Checking Feature Flags
 
+**Note:** Feature flags must be enabled in your Kinde application for the `feature_flags` attribute to be present in the token payload.
+
 ```javascript
🤖 Prompt for AI Agents
In src/content/docs/build/tokens/decode-jwts.mdx around lines 363 to 384, the
example accesses payload.feature_flags without documenting that this attribute
is optional and must be enabled in the Kinde dashboard; add a brief disclaimer
immediately above the "Checking Feature Flags" heading or directly before the
code block stating that feature_flags is an optional attribute that must be
enabled/configured in the Kinde dashboard (and will be absent otherwise), so
readers know to enable it before using the example; keep the note short and
place it as plain text (one or two sentences) before the code block.

Comment on lines +386 to +400
### Extracting Permissions

```javascript
import { jwtDecoder } from "@kinde/jwt-decoder"

export function getUserPermissions(token) {
try {
const payload = jwtDecoder(token)
return payload.permissions || []
} catch (error) {
console.error('Failed to extract permissions:', error)
return []
}
}
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add disclaimer for permissions attribute.

The "Extracting Permissions" example accesses payload.permissions without documenting that it may require enablement. Consistent with the email disclaimer in "Displaying User Information," add a note that permissions must be configured in the Kinde dashboard.

 ### Extracting Permissions
 
+**Note:** Permissions are included in the token payload by default when users have role-based permissions configured in Kinde. Ensure roles and permissions are set up in your Kinde application.
+
 ```javascript
🤖 Prompt for AI Agents
In src/content/docs/build/tokens/decode-jwts.mdx around lines 386 to 400, the
example reads payload.permissions but lacks the same disclaimer used for
displayed user info; add a short note directly above or below the "Extracting
Permissions" code block stating that the permissions attribute must be
enabled/configured in the Kinde dashboard (or via org settings) before it will
appear in the token, mirroring the wording/style used in the "Displaying User
Information" email disclaimer; keep the note concise and clearly linked to the
example so readers know to enable permissions in the dashboard if they receive
an empty array.

@tamalchowdhury
Copy link
Collaborator

@Arobce would you be willing to have another look at the overall structure of this guide? thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants